/// \file
#ifndef FILE_filehandle_H
#define FILE_filehandle_H

#include "inode.h"

typedef uint16_t filehandleid_t;

#define FS_FILE_HANDLES_ALLOCATED_DEFAULT 16
#define FS_FILE_HANDLES_ALLOCATED_MAx 16

/// Contains the data needed to use a file.
/// 
/// Currently, there cannot be multiple simultaneous reads.
typedef struct FileHandle_t_{
	bool isEmpty;
	inodeid_t fileId;
	inode_t inode;
	bool isReadOnly;
	bool isWriteOnly;
	filepos_t cursor;
}FileHandle_t;

/// The position from which the fs_seek function should look.
enum Seek_rel_t{
	/// Relative to the file first byte.
	FS_SEEK_SET = 0,
	/// Relative to the current file cursor position.
	FS_SEEK_CUR = 1,
	/// Relative to the file size (the byte after the last one).
	FS_SEEK_END = 2
};

/// Attempt to open a new file handle using the given inodeid, and
/// set handleId to the opened handleid.
///
/// You need to open a file before being able to edit it.
/// \note No flags are set during this operation, and the cursor is placed
/// at file start.
fs_ret_t fs_newFileHandle(FileSystemHandle_t *fsh, inodeid_t toOpen, filehandleid_t* handleId);

/// Sets handle to the pointer on the given handle.
///
/// Also tests to check if the handle is in fact opened.
fs_ret_t getFileHandle(FileSystemHandle_t *fsh,filehandleid_t handleId,FileHandle_t **handle);

// Remove the handle, and write the inode back to the disk.
fs_ret_t fs_deleteFileHandle(FileSystemHandle_t *fsh, filehandleid_t handleId);


/// Test whether the file is already opened.
///
/// The  handleId is set if it exists. Set the pointer to NULL if you don't
/// care about its id.
/// \return 0 if the file was not already opened.
fs_ret_t fs_inodeIsOpened(FileSystemHandle_t *fsh, inodeid_t toCheck, filehandleid_t* handleId);

/// Debug function writing byte at pos. 
/// \warning Do not use, it will be removed.
fs_ret_t fs_d_writeByte(FileSystemHandle_t *fsh, filehandleid_t handleId,filepos_t pos,byte_t byte);

/// Move the cursor in a file. 
///
/// pos can be either positive or negative, positive being towards the end 
/// of the file, and negative towards the begining.
/// \see enum Seek_rel_t
fs_ret_t fs_seek(FileSystemHandle_t *fsh, filehandleid_t handleId,enum Seek_rel_t fromWhere,filepos_t pos);

/// Returns the position relatively to the begining of the file into pos, in bytes.
fs_ret_t fs_tell(FileSystemHandle_t *fsh, filehandleid_t handleId,filepos_t* pos);

/// Sets size to the inode opened in the given fileHandle file size.
fs_ret_t fs_getSizeFromFileHandle(FileSystemHandle_t *fsh, filehandleid_t handleId, filepos_t *size);

/// Write the data pointed, at the current cursor position into the file.
/// \note The function always write all the bytes or is in an error state.
/// If it returns an error, no guarrantee is made regarding the number of bytes
/// written.
fs_ret_t fs_write(FileSystemHandle_t *fsh, filehandleid_t handleId, const byte_t* data, uint32_t dataSize);

/// Read the data for dataSize bytes from the file and write it into data.
/// \note The function reads all the characters it can before reaching the 
/// end of file.
fs_ret_t fs_read(FileSystemHandle_t *fsh, filehandleid_t handleId, byte_t* data, uint32_t dataSize);

/// Remove all of an handle's inode blocks, and set size to 0.
fs_ret_t fs_emptyItemwithHandle(FileSystemHandle_t *fsh, filehandleid_t handleId);

#ifdef __DEBUG__
fs_ret_t fs_getBlockForCursorPos(FileSystemHandle_t *fsh, FileHandle_t* handle, filepos_t cursor , blockid_t* blockNeeded);
#endif

#endif // FILE_filehandle_H

